﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Disposables;
using Rsdn.SmartApp;

namespace Rsdn.Janus
{
    public static class ForumMessageCommandHelper
    {
        /// <summary>
        /// Дефолтная логика получения статуса команды производящей операции над
        /// единственным сообщением.
        /// </summary>
        /// <param name="serviceProvider">The service provider.</param>
        /// <param name="messageId">The message id.</param>
        /// <returns></returns>
        public static CommandStatus GetSingleMessageCommandStatus(
               IServiceProvider serviceProvider, int? messageId)
        {
            if (messageId != null)
                return CommandStatus.Normal;

            IActiveMessagesService activeMessagesService = serviceProvider.GetService<IActiveMessagesService>();
            IEnumerable<IMsg> activeMessages = activeMessagesService.ActiveMessages;
            return activeMessagesService != null && activeMessages.Count() == 1
                ? CommandStatus.Normal
                : CommandStatus.Unavailable;
        }

        /// <summary>
        /// Дефолтная логика получения статуса команды производящей
        /// операции над одним или несколькими сообщениями форума.
        /// </summary>
        /// <param name="serviceProvider">The service provider.</param>
        /// <param name="messageIds">The message ids.</param>
        /// <returns></returns>
        public static CommandStatus GetMultipleMessagesCommandStatus(
            IServiceProvider serviceProvider, int[] messageIds)
        {
            if (messageIds != null)
            {
                return CommandStatus.Normal;
            }

            IActiveMessagesService activeMsgSvc = serviceProvider.GetService<IActiveMessagesService>();

            return activeMsgSvc != null && activeMsgSvc.ActiveMessages.Any()
                ? CommandStatus.Normal
                : CommandStatus.Unavailable;
        }

        /// <summary>
        /// Дефолтная логика подписки на оповешения о смене статуса команды.
        /// Обновление статуса происходит при возниконовении события сервиса
        /// <see cref="IActiveMessagesService.ActiveMessagesChanged"/>
        ///   <see cref="IActiveMessagesService"/>.
        /// </summary>
        /// <param name="serviceProvider">The service provider.</param>
        /// <param name="handler">The handler.</param>
        /// <returns></returns>
        public static IDisposable SubscribeMessageCommandStatusChanged(
            IServiceProvider serviceProvider, Action handler)
        {
            var activeMsgSvc = serviceProvider.GetService<IActiveMessagesService>();
            if (activeMsgSvc != null)
            {
                EventHandler statusUpdater = delegate { handler(); };
                activeMsgSvc.ActiveMessagesChanged += statusUpdater;

                Action dispose = 
                    delegate
                        {
                            activeMsgSvc.ActiveMessagesChanged -= statusUpdater;
                        };

                return Disposable.Create(dispose);
            }
            return Disposable.Empty;
        }

        /// <summary>
        /// Возвращает сообщение с указанным идентификатором,
        /// либо если идентификатор не указан, возвращает текущее активное сообщение.
        /// </summary>
        /// <param name="serviceProvider">The service provider.</param>
        /// <param name="messageId">The message id.</param>
        /// <returns></returns>
        public static IMsg GetMessage(IServiceProvider serviceProvider, int? messageId)
        {
            IActiveMessagesService activeMessagesService = serviceProvider.GetRequiredService<IActiveMessagesService>();
            IEnumerable<IMsg> activeMessages = activeMessagesService.ActiveMessages;
            return messageId != null
                ? DatabaseManager.GetMessageWithForum(serviceProvider, messageId.Value)
                : activeMessages.Single();
        }

        /// <summary>
        /// Возвращает указанный идентификатор сообщения,
        /// либо если идентификатор не указан, возвращает идентификатор текущего активного сообщения.
        /// </summary>
        /// <param name="serviceProvider">The service provider.</param>
        /// <param name="messageId">The message id.</param>
        /// <returns></returns>
        public static int GetMessageId(IServiceProvider serviceProvider, int? messageId)
        {
            var activeMessagesService = serviceProvider.GetRequiredService<IActiveMessagesService>();
            IEnumerable<IMsg> activeMessages = activeMessagesService.ActiveMessages;
            IMsg single = activeMessages.Single();
            return (int)(messageId != null ? messageId : single.ID);
        }

        /// <summary>
        /// Возвращает сообщения с указанными идентификаторами, либо если
        /// идентификаторы не указаны, возвращает текущие выделенные сообщения.
        /// </summary>
        /// <param name="serviceProvider">The service provider.</param>
        /// <param name="messageIds">The message ids.</param>
        /// <returns></returns>
        public static IEnumerable<IMsg> GetMessages(
            IServiceProvider serviceProvider,
            IEnumerable<int> messageIds)
        {
            IActiveMessagesService activeMessagesService = serviceProvider.GetRequiredService<IActiveMessagesService>();
            return messageIds != null
                       ? messageIds.Select(msgId => (IMsg)DatabaseManager.GetMessageWithForum(serviceProvider, msgId))
                       : activeMessagesService.ActiveMessages;
        }

        /// <summary>
        /// Возвращает указанные идентификаторы сообщений, либо если идентификаторы
        /// не указаны, возвращает идентификаторы текущих активных сообщений.
        /// </summary>
        /// <param name="serviceProvider">The service provider.</param>
        /// <param name="messageIds">The message ids.</param>
        /// <returns></returns>
        /// <exception cref="System.ArgumentNullException">source or selector is null.</exception>
        public static IEnumerable<int> GetMessageIds(
            IServiceProvider serviceProvider, IEnumerable<int> messageIds)
        {
            IActiveMessagesService activeMessagesService = serviceProvider.GetRequiredService<IActiveMessagesService>();
            IEnumerable<IMsg> activeMessages = activeMessagesService.ActiveMessages;
            return messageIds != null ? messageIds : activeMessages.Select(msg => msg.ID);
        }

        /// <summary>
        /// Проверка актуальности установки пометки о прочтении.
        /// </summary>
        /// <param name="msg">The MSG.</param>
        /// <param name="isRead">if set to <c>true</c> [is read].</param>
        /// <param name="withReplies">if set to <c>true</c> [with replies].</param>
        /// <returns>
        /// 	<c>true</c> if this instance [can set message read mark] the specified MSG; otherwise, <c>false</c>.
        /// </returns>
        public static bool CanSetMessageReadMark(this IMsg msg, bool isRead, bool withReplies)
        {
            // TODO: Заплата
            if (msg == null)
            {
                return false;
            }

            if (msg.IsUnread == isRead)
            {
                return true;
            }

            if (!withReplies)
            {
                return false;
            }

            return isRead
                ? msg.RepliesUnread > 0
                : msg.RepliesUnread < msg.RepliesCount;
        }
    }
}
